package com.shuyixiao.javan8nv1.core;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shuyixiao.javan8nv1.model.*;
import com.shuyixiao.javan8nv1.mapper.NodeMapper;
import com.shuyixiao.javan8nv1.mapper.ConnectionMapper;
import com.shuyixiao.javan8nv1.registry.NodeRegistry;
import com.shuyixiao.javan8nv1.registry.NodeType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WorkflowEngine {
    @Autowired
    private NodeMapper nodeMapper;
    @Autowired
    private ConnectionMapper connectionMapper;
    @Autowired
    private NodeRegistry nodeRegistry;

    private final ObjectMapper objectMapper = new ObjectMapper();

    public ExecutionResult executeWorkflow(Workflow workflow, ExecutionContext initialContext) {
        validateWorkflow(workflow);
        ExecutionGraph graph = buildExecutionGraph(workflow);
        return executeGraph(graph, initialContext);
    }

    private void validateWorkflow(Workflow workflow) {
        // TODO: 校验流程结构、节点参数等
    }

    private ExecutionGraph buildExecutionGraph(Workflow workflow) {
        ExecutionGraph graph = new ExecutionGraph();
        List<Node> nodes = nodeMapper.selectList(new QueryWrapper<Node>().eq("workflow_id", workflow.getId()));
        List<Connection> connections = connectionMapper.selectList(new QueryWrapper<Connection>().eq("workflow_id", workflow.getId()));

        Map<String, Node> nodeMap = nodes.stream().collect(Collectors.toMap(Node::getName, node -> node, (a, b) -> a));
        graph.getNodes().putAll(nodeMap);

        for (Connection conn : connections) {
            Node source = nodeMap.get(conn.getSourceNodeName());
            Node target = nodeMap.get(conn.getTargetNodeName());
            if (source != null && target != null) {
                graph.getOutgoingConnections().computeIfAbsent(source.getName(), k -> new ArrayList<>()).add(conn);
                graph.getIncomingConnections().computeIfAbsent(target.getName(), k -> new ArrayList<>()).add(conn);
            }
        }
        return graph;
    }

    private ExecutionResult executeGraph(ExecutionGraph graph, ExecutionContext context) {
        Queue<Node> executionQueue = new LinkedList<>();
        Set<String> completedNodes = new HashSet<>();

        // 1. 找到所有起始节点（没有入度的节点）
        Set<String> allNodesWithInputs = graph.getIncomingConnections().keySet();
        List<Node> startNodes = graph.getNodes().values().stream()
                .filter(node -> !allNodesWithInputs.contains(node.getName()))
                .collect(Collectors.toList());

        // 2. 对起始节点按 v1 规则排序并加入队列
        sortNodesV1(startNodes);
        executionQueue.addAll(startNodes);
        
        // 3. 开始数据驱动的执行循环
        while (!executionQueue.isEmpty()) {
            Node currentNode = executionQueue.poll();
            if (completedNodes.contains(currentNode.getName())) {
                continue;
            }

            // 4. 准备当前节点的输入数据
            Map<String, List<Object>> inputs = prepareNodeInputs(currentNode, graph, context);

            // 5. 执行节点
            NodeType nodeType = nodeRegistry.getNodeType(currentNode.getType());
            NodeExecutionResult result = nodeType.execute(currentNode, inputs);
            context.addNodeResult(currentNode.getName(), result);
            completedNodes.add(currentNode.getName());
            
            // 6. 如果执行失败，则不继续触发下游节点
            if ("error".equals(result.getStatus())) {
                continue;
            }

            // 7. 找到并准备执行下游节点
            List<Connection> outgoingConnections = graph.getOutgoingConnections().getOrDefault(currentNode.getName(), Collections.emptyList());
            Map<String, List<Object>> outputData = result.getOutputData();

            if (outputData == null || outputData.isEmpty()) {
                continue;
            }

            // 对输出端口进行排序，确保处理顺序稳定
            List<String> sortedOutputNames = new ArrayList<>(outputData.keySet());
            Collections.sort(sortedOutputNames);

            for (String outputName : sortedOutputNames) {
                List<Node> downstreamNodes = outgoingConnections.stream()
                        .filter(conn -> conn.getSourceOutput().equals(outputName) || "main".equals(conn.getSourceOutput())) // 简化匹配
                        .map(conn -> graph.getNodes().get(conn.getTargetNodeName()))
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());

                // 按 v1 规则排序下游节点
                sortNodesV1(downstreamNodes);

                for (Node nextNode : downstreamNodes) {
                    // 检查下游节点的所有上游依赖是否都已完成
                    boolean allDependenciesMet = graph.getIncomingConnections().getOrDefault(nextNode.getName(), Collections.emptyList())
                            .stream()
                            .allMatch(conn -> completedNodes.contains(conn.getSourceNodeName()));
                    
                    if (allDependenciesMet) {
                        executionQueue.offer(nextNode);
                    }
                }
            }
        }
        return new ExecutionResult(context);
    }

    private Map<String, List<Object>> prepareNodeInputs(Node node, ExecutionGraph graph, ExecutionContext context) {
        Map<String, List<Object>> inputs = new HashMap<>();
        List<Connection> incomingConnections = graph.getIncomingConnections().getOrDefault(node.getName(), Collections.emptyList());

        for (Connection conn : incomingConnections) {
            NodeExecutionResult upstreamResult = context.getNodeResult(conn.getSourceNodeName());
            if (upstreamResult != null && upstreamResult.getOutputData() != null) {
                List<Object> data = upstreamResult.getOutputData().get(conn.getSourceOutput());
                if (data != null) {
                    inputs.computeIfAbsent(conn.getTargetInput(), k -> new ArrayList<>()).addAll(data);
                }
            }
        }
        return inputs;
    }
    
    private void sortNodesV1(List<Node> nodes) {
        nodes.sort(Comparator.comparing(node -> {
            try {
                Map<String, Integer> pos = objectMapper.readValue(node.getPosition(), new TypeReference<>() {});
                return new int[]{pos.getOrDefault("x", 0), pos.getOrDefault("y", 0)};
            } catch (JsonProcessingException | NullPointerException e) {
                return new int[]{0, 0};
            }
        }, (pos1, pos2) -> {
            if (pos1[1] != pos2[1]) return Integer.compare(pos1[1], pos2[1]); // Y 优先
            return Integer.compare(pos1[0], pos2[0]); // X 其次
        }));
    }
} 